home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Programming / tek / kn / sockcommon / waitservsock.c < prev   
C/C++ Source or Header  |  2001-05-12  |  12KB  |  506 lines

  1.  
  2. static int servprocwrite(struct knservsocket *s, struct knsrvnode *cnode);
  3. static int servprocread(struct knservsocket *s, struct knsrvnode *cnode);
  4.  
  5. /*
  6. **    newmsg = kn_waitservsock(sock, event)
  7. **
  8. **    process messages from socket and wait for an event to occur.
  9. **    returns the number of new messages that are ready for delivery.
  10. **
  11. */
  12.  
  13. TUINT kn_waitservsock(TAPTR knsock, TKNOB *event)
  14. {
  15.     struct knservsocket *s = (struct knservsocket *) knsock;
  16.     kn_sockenv_t *sockenv = &s->sockenv;
  17.  
  18.     int i;
  19.     struct knsrvnode *cnode;
  20.     TNODE *nextnode, *node;
  21.     int numready;
  22.     TUINT numdeliver = 0;
  23.     TBOOL signal_occured;
  24.     TTIME now;
  25.     TFLOAT nowf;
  26.  
  27.     do
  28.     {
  29.         struct timeval waittimeout = {0, TIMEOUT_USEC};
  30.  
  31.         fd_set tempreadset, tempwriteset;
  32.         
  33.         if (TListEmpty(&s->freelist))
  34.         {
  35.             FD_CLR(s->desc, &s->readset);
  36.  
  37.             node = s->writelist.head;
  38.             while ((nextnode = node->succ))
  39.             {
  40.                 cnode = (struct knsrvnode *) node;
  41.                 servprocwrite(s, cnode);
  42.                 node = nextnode;
  43.             }
  44.  
  45.             node = s->readlist.head;
  46.             while ((nextnode = node->succ))
  47.             {
  48.                 cnode = (struct knsrvnode *) node;
  49.                 numdeliver += servprocread(s, cnode);
  50.                 node = nextnode;
  51.             }
  52.  
  53.             if (numdeliver) return numdeliver;
  54.  
  55.         }
  56.         else
  57.         {
  58.             FD_SET(s->desc, &s->readset);
  59.         }
  60.  
  61.         tempreadset = s->readset;
  62.         tempwriteset = s->writeset;
  63.  
  64.         kn_locksock(sockenv);
  65.         
  66.         numready = kn_waitselect(sockenv, FD_SETSIZE, &tempreadset, &tempwriteset, NULL, &waittimeout, event, &signal_occured);
  67.  
  68.         kn_unlocksock(sockenv);
  69.  
  70.         if (numready > 0)
  71.         {
  72.             for (i = 0; i < FD_SETSIZE; ++i)
  73.             {
  74.                 if (FD_ISSET(i, &tempreadset))
  75.                 {
  76.                     if (i == s->desc)    /* connection on server socket */
  77.                     {
  78.                         cnode = (struct knsrvnode *) TRemHead(&s->freelist);
  79.                         if (cnode)
  80.                         {
  81.                             int namesize = sizeof(struct sockaddr_in);
  82.                             
  83.                             kn_locksock(sockenv);
  84.                             
  85.                             cnode->desc = accept(s->desc, (struct sockaddr *) &cnode->sendername, &namesize);
  86.                             if (cnode->desc >= 0)
  87.                             {
  88.                                 char *t, *d;
  89.  
  90.                                 kn_socknonblocking(cnode->desc);
  91.                                 
  92.                                 FD_SET(cnode->desc, &s->readset);
  93.                                 cnode->bytesdone = 0;
  94.                                 cnode->bufmsg = TNULL;
  95.                                 cnode->connID = s->connID++;
  96.                                 cnode->netmsg.backptr = cnode;
  97.                                 cnode->netmsg.sendername = &cnode->sendername;
  98.  
  99.                                 /* generate sender name string */
  100.                                 
  101.                                 t = kn_getsockname(&cnode->sendername);
  102.                                 d = cnode->netmsg.symbolicname;
  103.                                 while ((*d++ = *t++));
  104.                                 *(d - 1) = ':';
  105.                                 kn_itoa((int) kn_getsockport(&cnode->sendername), d);
  106.  
  107.  
  108.                                 /* insert timestamp */
  109.                                 
  110.                                 kn_querytimer(s->timer, &now);
  111.                                 cnode->timestamp = TTIMETOF(&now);
  112.                                 
  113.                                 TAddTail(&s->readlist, (TNODE *) cnode);
  114.                                 dbsprintf(5, "*** TEKLIB kn_waitsock: added new connection to readlist\n");
  115.                             }
  116.                             else
  117.                             {
  118.                                 dbsprintf(10, "*** TEKLIB kn_waitsock: accept()\n");
  119.                                 TAddHead(&s->freelist, (TNODE *) cnode);
  120.                             }
  121.  
  122.                             kn_unlocksock(sockenv);
  123.                         }
  124.                         else 
  125.                         {
  126.                             dbsprintf(10, "*** TEKLIB kn_waitsock: no free clientnode for accepting a connection\n");
  127.                         }
  128.                     }
  129.                     else    /* data pending on a read connection */
  130.                     {
  131.                         node = s->readlist.head;
  132.                         while ((nextnode = node->succ))
  133.                         {
  134.                             cnode = (struct knsrvnode *) node;
  135.                             if (i == cnode->desc)
  136.                             {
  137.                                 kn_querytimer(s->timer, &now);
  138.                                 cnode->timestamp = TTIMETOF(&now);
  139.  
  140.                                 numdeliver += servprocread(s, cnode);
  141.                                 break;
  142.                             }
  143.                             node = nextnode;
  144.                         }
  145.                     }
  146.                 }
  147.                 else if (FD_ISSET(i, &tempwriteset))    /* data can be written */
  148.                 {
  149.                     node = s->writelist.head;
  150.                     while ((nextnode = node->succ))
  151.                     {
  152.                         cnode = (struct knsrvnode *) node;
  153.                         if (i == cnode->desc)
  154.                         {
  155.                             servprocwrite(s, cnode);
  156.                             break;
  157.                         }
  158.                         node = nextnode;
  159.                     }
  160.                 }
  161.             }
  162.         }
  163.         else if (numready < 0)
  164.         {
  165.             dbsprintf(10, "*** TEKLIB kn_waitsock: select()\n");
  166.         }
  167.  
  168.  
  169.     
  170.         /*    handle timeout on readlist */
  171.  
  172.         node = s->readlist.head;
  173.  
  174.         kn_querytimer(s->timer, &now);
  175.         nowf = TTIMETOF(&now);
  176.  
  177.         dbsprintf(1, "*** TEKLIB kn_waitservsock: checking timeouts on readlist\n");
  178.  
  179.         while ((nextnode = node->succ))
  180.         {
  181.             cnode = (struct knsrvnode *) node;
  182.             if (nowf - cnode->timestamp > s->readtimeout)
  183.             {
  184.                 dbsprintf(10, "*** TEKLIB kn_waitservsock: lazy client timeout\n");
  185.  
  186.                 TRemove(node);
  187.                 FD_CLR(cnode->desc, &s->readset);
  188.  
  189.                 kn_locksock(sockenv);
  190.                 shutdown(cnode->desc, 2);
  191.                 kn_closesocket(cnode->desc);
  192.                 kn_unlocksock(sockenv);
  193.  
  194.                 TAddTail(&s->freelist, (TNODE *) cnode);
  195.             }
  196.             node = nextnode;
  197.         }
  198.  
  199.     
  200.     } while (!numdeliver && !signal_occured);
  201.     
  202.     return numdeliver;
  203. }
  204.  
  205.  
  206.  
  207. /*
  208. **    completed = servprocwrite(knservsock, knsrvnode)
  209. **
  210. **    write pending data from a server socket's connection node.
  211. **
  212. */
  213.  
  214. static int servprocwrite(struct knservsocket *s, struct knsrvnode *cnode)
  215. {
  216.     kn_sockenv_t *sockenv = &s->sockenv;
  217.  
  218.     int numwritten;
  219.  
  220.     if (cnode->bytesdone < sizeof(knnethead))
  221.     {
  222.         /* write msg header */
  223.  
  224.         kn_locksock(sockenv);
  225.         
  226.         numwritten = send(cnode->desc,
  227.             ((char *) &cnode->netmsg.nethead) + cnode->bytesdone,
  228.             sizeof(knnethead) - cnode->bytesdone, KNSOCK_SENDFLAGS);
  229.  
  230.         kn_unlocksock(sockenv);
  231.         
  232.         if (numwritten < 0)
  233.         {
  234.             if (kn_getsockerrno(sockenv, cnode->desc) != EWOULDBLOCK)
  235.             {
  236.                 dbsprintf(10, "*** TEKLIB servprocwrite send(1): dropping connection due to unexpected error\n");
  237.             
  238.                 TRemove((TNODE *) cnode);
  239.  
  240.                 TFreeMsg(cnode->bufmsg + 1);
  241.  
  242.                 kn_locksock(sockenv);
  243.                 shutdown(cnode->desc, 2);
  244.                 kn_closesocket(cnode->desc);
  245.                 kn_unlocksock(sockenv);
  246.  
  247.                 TAddTail(&s->freelist, (TNODE *) cnode);
  248.                 FD_CLR(cnode->desc, &s->writeset);
  249.             }
  250.             else dbsprintf(2, "*** TEKLIB servprocwrite send(1): would block\n");
  251.  
  252.             return 0;            /* msg header not yet complete, but no more data pending */
  253.         }
  254.  
  255.         cnode->bytesdone += numwritten;
  256.         
  257.         if (cnode->bytesdone == sizeof(knnethead))
  258.         {
  259.             if (cnode->bytesdone == cnode->bytestowrite)
  260.             {
  261.                 /* header-only msg complete */
  262.  
  263.                 TRemove((TNODE *) cnode);
  264.                 cnode->bytesdone = 0;
  265.                 TAddTail(&s->readlist, (TNODE *) cnode);
  266.                 FD_CLR(cnode->desc, &s->writeset);
  267.                 FD_SET(cnode->desc, &s->readset);
  268.                 return 1;
  269.             }
  270.         }
  271.         else
  272.         {
  273.             return 0;            /* msg header not yet complete, but no more data pending */
  274.         }
  275.     }
  276.     
  277.  
  278.     /*    write msg body */
  279.  
  280.     kn_locksock(sockenv);
  281.     
  282.     numwritten = send(cnode->desc,
  283.         ((char *) cnode->bufmsg) + cnode->bytesdone + sizeof(TMSG) - sizeof(knnethead),
  284.         cnode->bytestowrite - cnode->bytesdone, KNSOCK_SENDFLAGS);
  285.  
  286.     kn_unlocksock(sockenv);
  287.     
  288.     if (numwritten < 0)
  289.     {
  290.         if (kn_getsockerrno(sockenv, cnode->desc) != EWOULDBLOCK)
  291.         {
  292.             dbsprintf(10, "*** TEKLIB: servprocwrite: dropping connection due to unexpected error\n");
  293.             TRemove((TNODE *) cnode);
  294.  
  295.             TFreeMsg(cnode->bufmsg + 1);
  296.             
  297.             kn_locksock(sockenv);
  298.             shutdown(cnode->desc, 2);
  299.             kn_closesocket(cnode->desc);
  300.             kn_unlocksock(sockenv);
  301.  
  302.             TAddTail(&s->freelist, (TNODE *) cnode);
  303.             FD_CLR(cnode->desc, &s->writeset);
  304.         }
  305.         else dbsprintf(2, "*** TEKLIB servprocwrite: send(2) would block\n");
  306.  
  307.         return 0;
  308.     }
  309.     
  310.     cnode->bytesdone += numwritten;
  311.  
  312.     if (cnode->bytesdone == cnode->bytestowrite)
  313.     {
  314.         /* msg complete */
  315.  
  316.         dbsprintf(3, "*** servprocwrite: msg written back\n");
  317.         TRemove((TNODE *) cnode);
  318.  
  319.         TFreeMsg(cnode->bufmsg + 1);
  320.  
  321.         cnode->bufmsg = TNULL;
  322.         cnode->bytesdone = 0;
  323.         TAddTail(&s->readlist, (TNODE *) cnode);
  324.         FD_CLR(cnode->desc, &s->writeset);
  325.         FD_SET(cnode->desc, &s->readset);
  326.  
  327.         return 1;
  328.     }
  329.  
  330.     return 0;
  331. }
  332.  
  333.  
  334.  
  335. /*
  336. **    more_data_to_expect = servprocread(knservsock, knsrvnode)
  337. **
  338. **    read pending data from a server socket's connection node.
  339. **    finished messages will be linked to the server socket's deliver list.
  340. */
  341.  
  342. static int servprocread(struct knservsocket *s, struct knsrvnode *cnode)
  343. {
  344.     kn_sockenv_t *sockenv = &s->sockenv;
  345.  
  346.     int numread;
  347.     TUINT size, proto, version;
  348.  
  349.     if (cnode->bytesdone < sizeof(knnethead))
  350.     {
  351.         /*    read msg header */
  352.  
  353.         kn_locksock(sockenv);
  354.  
  355.         numread = recv(cnode->desc,
  356.             ((char *) &cnode->netmsg.nethead) + cnode->bytesdone, 
  357.             sizeof(knnethead) - cnode->bytesdone, KNSOCK_RECVFLAGS);
  358.  
  359.         kn_unlocksock(sockenv);
  360.     
  361.         if (numread <= 0)
  362.         {
  363.             int sockerr = kn_getsockerrno(sockenv, cnode->desc);
  364.         
  365.             if (numread == 0 || sockerr != EWOULDBLOCK)
  366.             {
  367.                 if (numread == 0)
  368.                 {
  369.                     dbsprintf(5, "*** TEKLIB servprocread(1): end-of-file on descriptor - dropping connection\n");
  370.                 }
  371.                 else if (sockerr != EWOULDBLOCK)
  372.                 {
  373.                     dbsprintf(20, "*** TEKLIB servprocread(1): unexpected error on descriptor - dropping connection\n");
  374.                 }
  375.  
  376.                 TRemove((TNODE *) cnode);
  377.                 FD_CLR(cnode->desc, &s->readset);
  378.  
  379.                 kn_locksock(sockenv);
  380.                 shutdown(cnode->desc, 2);
  381.                 kn_closesocket(cnode->desc);
  382.                 kn_unlocksock(sockenv);
  383.  
  384.                 TAddTail(&s->freelist, (TNODE *) cnode);
  385.             }
  386.             else dbsprintf(2, "*** TEKLIB servprocread: recv(1) would block\n");
  387.  
  388.             return 0;    /* msg header not yet complete, but no more data pending */
  389.         }
  390.         
  391.         cnode->bytesdone += numread;
  392.         
  393.         if (cnode->bytesdone == sizeof(knnethead))
  394.         {
  395.             size = cnode->netmsg.nethead.msgsize = ntohl(cnode->netmsg.nethead.msgsize);
  396.             proto = (TUINT) cnode->netmsg.nethead.protocol;
  397.             version = (TUINT) cnode->netmsg.nethead.version;
  398.             
  399.             if (version == KNSOCK_VERSION && (proto == KNSOCK_PROTO_PUT || proto == KNSOCK_PROTO_PUTREPLY))
  400.             {
  401.                 if (size >= sizeof(knnethead) && size <= s->maxmsgsize + sizeof(knnethead))
  402.                 {
  403.                     /*if ((cnode->bufmsg = TMMUAlloc(s->mmu, size - sizeof(knnethead) + sizeof(TMSG))))*/
  404.                     if ((cnode->bufmsg = TMMUAlloc(s->msgmmu, size - sizeof(knnethead))))
  405.                     {
  406.                         cnode->bufmsg--;
  407.                         dbsprintf(2, "*** TEKLIB servprocread: allocated message\n");
  408.                     }
  409.                     else
  410.                     {
  411.                         dbsprintf(10, "*** TEKLIB servprocread: cannot allocate memory for message\n");
  412.                     }
  413.                 } else dbsprintf(20, "*** TEKLIB servprocread: message has illegal size\n");
  414.             } else dbsprintf(20, "*** TEKLIB servprocread: unknown/invalid message protocol\n");
  415.             
  416.             if (!cnode->bufmsg)
  417.             {
  418.                 /* 
  419.                 **    illegal protocol, out of memory or msg has illegal size.
  420.                 **    drop this connection, and put the connection node back to freelist
  421.                 */
  422.         
  423.                 dbsprintf(20, "*** TEKLIB: servprocread: illegal protocol / msg size - dropping connection\n");
  424.         
  425.                 TRemove((TNODE *) cnode);
  426.                 FD_CLR(cnode->desc, &s->readset);
  427.  
  428.                 kn_locksock(sockenv);
  429.                 shutdown(cnode->desc, 2);
  430.                 kn_closesocket(cnode->desc);
  431.                 kn_unlocksock(sockenv);
  432.  
  433.                 TAddTail(&s->freelist, (TNODE *) cnode);
  434.                 return 0;
  435.             }
  436.             
  437.             dbsprintf(2, "*** TEKLIB servprocread: header complete, continue with msg body\n");
  438.         }
  439.         else
  440.         {
  441.             dbsprintf(3, "*** TEKLIB servprocread: header not read in a single operation\n");
  442.             return 0;            /* msg header not yet complete, but no more data pending */
  443.         }
  444.     }
  445.  
  446.  
  447.     if (cnode->bytesdone < cnode->netmsg.nethead.msgsize)
  448.     {
  449.         /*    read msg body */
  450.  
  451.         kn_locksock(sockenv);
  452.     
  453.         numread = recv(cnode->desc,
  454.             ((char *) cnode->bufmsg) + cnode->bytesdone - sizeof(knnethead) + sizeof(TMSG),
  455.             cnode->netmsg.nethead.msgsize - cnode->bytesdone, KNSOCK_RECVFLAGS);
  456.  
  457.         kn_unlocksock(sockenv);
  458.  
  459.         if (numread <= 0)
  460.         {
  461.             int sockerr = kn_getsockerrno(sockenv, cnode->desc);
  462.         
  463.             if (numread == 0 || sockerr != EWOULDBLOCK)
  464.             {
  465.                 if (numread == 0)
  466.                 {
  467.                     dbsprintf(5, "*** TEKLIB servprocread(2): end-of-file on descriptor - dropping connection\n");
  468.                 }
  469.                 else if (sockerr != EWOULDBLOCK)
  470.                 {
  471.                     dbsprintf(20, "*** TEKLIB servprocread(2): unexpected error on descriptor - dropping connection\n");
  472.                 }
  473.  
  474.                 TRemove((TNODE *) cnode);
  475.                 FD_CLR(cnode->desc, &s->readset);
  476.  
  477.                 TFreeMsg(cnode->bufmsg + 1);
  478.                 
  479.                 kn_locksock(sockenv);
  480.                 shutdown(cnode->desc, 2);
  481.                 kn_closesocket(cnode->desc);
  482.                 kn_unlocksock(sockenv);
  483.  
  484.                 TAddTail(&s->freelist, (TNODE *) cnode);
  485.             }
  486.             else dbsprintf(2, "*** TEKLIB servprocread: recv(2) would block\n");
  487.  
  488.             return 0;    /* msg header not yet complete, but no more data pending */
  489.         }
  490.         
  491.         cnode->bytesdone += numread;
  492.     }
  493.  
  494.     if (cnode->bytesdone == cnode->netmsg.nethead.msgsize)
  495.     {
  496.         /* msg complete - link to deliver list */
  497.  
  498.         FD_CLR(cnode->desc, &s->readset);
  499.         TRemove((TNODE *) cnode);
  500.         TAddTail(&s->deliverlist, (TNODE *) cnode);
  501.         return 1;
  502.     }
  503.  
  504.     return 0;
  505. }
  506.